<script lang="ts" setup>
import EntityDropdownItems from "@/components/entity/EntityDropdownItems.vue";
import { useOperationItemExtensionPoint } from "@console/composables/use-operation-extension-points";
import type { Attachment } from "@halo-dev/api-client";
import { coreApiClient } from "@halo-dev/api-client";
import {
  Dialog,
  Toast,
  VDropdownDivider,
  VDropdownItem,
  VEntity,
  VEntityField,
  VSpace,
  VStatusDot,
} from "@halo-dev/components";
import { utils, type OperationItem } from "@halo-dev/ui-shared";
import { useQueryClient } from "@tanstack/vue-query";
import prettyBytes from "pretty-bytes";
import type { Ref } from "vue";
import { computed, inject, markRaw, ref, toRefs } from "vue";
import { useI18n } from "vue-i18n";
import { useFetchAttachmentPolicy } from "../composables/use-attachment-policy";

const { t } = useI18n();
const queryClient = useQueryClient();

const props = withDefaults(
  defineProps<{
    attachment: Attachment;
    isSelected?: boolean;
  }>(),
  { isSelected: false }
);

const { attachment } = toRefs(props);

const { policies } = useFetchAttachmentPolicy();

const emit = defineEmits<{
  (event: "select", attachment?: Attachment): void;
  (event: "open-detail", attachment: Attachment): void;
}>();

const selectedAttachmentNames = inject<Ref<Set<string>>>(
  "selectedAttachmentNames",
  ref<Set<string>>(new Set())
);

const policyDisplayName = computed(() => {
  const policy = policies.value?.find(
    (p) => p.metadata.name === props.attachment.spec.policyName
  );
  return policy?.spec.displayName;
});

const handleDelete = () => {
  Dialog.warning({
    title: t("core.attachment.operations.delete.title"),
    description: t("core.common.dialog.descriptions.cannot_be_recovered"),
    confirmType: "danger",
    confirmText: t("core.common.buttons.confirm"),
    cancelText: t("core.common.buttons.cancel"),
    onConfirm: async () => {
      try {
        await coreApiClient.storage.attachment.deleteAttachment({
          name: props.attachment.metadata.name,
        });

        selectedAttachmentNames.value.delete(props.attachment.metadata.name);

        Toast.success(t("core.common.toast.delete_success"));
      } catch (e) {
        console.error("Failed to delete attachment", e);
      } finally {
        queryClient.invalidateQueries({ queryKey: ["attachments"] });
      }
    },
  });
};

const { data: operationItems } = useOperationItemExtensionPoint<Attachment>(
  "attachment:list-item:operation:create",
  attachment,
  computed((): OperationItem<Attachment>[] => [
    {
      priority: 10,
      component: markRaw(VDropdownItem),
      label: t("core.common.buttons.detail"),
      permissions: [],
      action: () => {
        emit("open-detail", attachment.value);
      },
    },
    {
      priority: 20,
      component: markRaw(VDropdownItem),
      label: t("core.common.buttons.download"),
      action: () => {
        const { permalink } = attachment.value.status || {};

        if (!permalink) {
          throw new Error("Attachment has no permalink");
        }

        const a = document.createElement("a");
        a.href = permalink;
        a.download = attachment.value.spec.displayName || "unknown";
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
      },
    },
    {
      priority: 30,
      component: markRaw(VDropdownDivider),
    },
    {
      priority: 40,
      component: markRaw(VDropdownItem),
      props: {
        type: "danger",
      },
      label: t("core.common.buttons.delete"),
      permissions: ["system:attachments:manage"],
      action: () => {
        handleDelete();
      },
    },
  ])
);
</script>

<template>
  <VEntity :is-selected="isSelected">
    <template
      v-if="utils.permission.has(['system:attachments:manage'])"
      #checkbox
    >
      <input
        :checked="selectedAttachmentNames.has(attachment.metadata.name)"
        type="checkbox"
        @click="emit('select', attachment)"
      />
    </template>
    <template #start>
      <VEntityField>
        <template #description>
          <div class="h-10 w-10 rounded border bg-white p-1 hover:shadow-sm">
            <AttachmentFileTypeIcon
              :display-ext="false"
              :file-name="attachment.spec.displayName"
              :width="8"
              :height="8"
            />
          </div>
        </template>
      </VEntityField>
      <VEntityField
        :title="attachment.spec.displayName"
        @click="emit('open-detail', attachment)"
      >
        <template #description>
          <VSpace>
            <span class="text-xs text-gray-500">
              {{ attachment.spec.mediaType }}
            </span>
            <span class="text-xs text-gray-500">
              {{ prettyBytes(attachment.spec.size || 0) }}
            </span>
          </VSpace>
        </template>
      </VEntityField>
    </template>
    <template #end>
      <VEntityField :description="policyDisplayName" />
      <VEntityField>
        <template #description>
          <RouterLink
            :to="{
              name: 'UserDetail',
              params: {
                name: attachment.spec.ownerName,
              },
            }"
            class="text-xs text-gray-500"
            :class="{
              'pointer-events-none': !utils.permission.has([
                'system:users:view',
              ]),
            }"
          >
            {{ attachment.spec.ownerName }}
          </RouterLink>
        </template>
      </VEntityField>
      <VEntityField v-if="attachment.metadata.deletionTimestamp">
        <template #description>
          <VStatusDot
            v-tooltip="$t('core.common.status.deleting')"
            state="warning"
            animate
          />
        </template>
      </VEntityField>
      <VEntityField>
        <template #description>
          <span class="truncate text-xs tabular-nums text-gray-500">
            {{ utils.date.format(attachment.metadata.creationTimestamp) }}
          </span>
        </template>
      </VEntityField>
    </template>
    <template #dropdownItems>
      <EntityDropdownItems
        :dropdown-items="operationItems || []"
        :item="attachment"
      />
    </template>
  </VEntity>
</template>
